%{

#include <cstdio>
#include <cstdlib>
#include <vector>
#include <string>
#include <list>
#include <utility>  
#include <cstddef>
#include <map>

//includes relatifs à notre structure de données
#include "../../parseur/DTD/tree/DtdNode.h"
#include "../../parseur/DTD/tree/DtdElement.h"
#include "../../parseur/DTD/tree/DtdComposite.h"
#include "../../parseur/DTD/tree/DtdDeclaration.h"
#include "../../parseur/DTD/tree/DtdTree.h"


int dtd_wrap(void);
void dtd_error(DtdTree ** arbreDTD,char *msg);
int dtd_lex(void);


%}

%union {

char *s;
DtdNode *a;
enum NodeCard *nCard;
std::list<DtdNode*> *nodes;
DtdNode *node;
std::pair<enum ElementType, DtdComposite*> *declarationPair;
DtdDeclaration *dec;

}

%token ELEMENT ATTLIST SUP OUVREPAR FERMEPAR VIRGULE BARRE FIXED EMPTY ANY PCDATA AST PTINT PLUS CDATA
%token <s> NOM TOKENTYPE DECLARATION VALEUR
%type <nCard> card_opt ast_opt
%type <node> cp children seq choice mixed
%type <nodes> liste_choice liste_seq_opt barre_nom
%type <declarationPair> contentspec
%type <dec> element

%parse-param {DtdTree** arbreDTD}
%%

main: dtd_list_opt {(*arbreDTD)->buildTreeStructure();}
;

dtd_list_opt
: dtd_list_opt ATTLIST NOM att_definition_opt SUP { }
| dtd_list_opt element {(*arbreDTD)->addDeclaration($2);}
| /* vide */ {printf("let's start...\n"); }
;

att_definition_opt
: att_definition_opt attribut { }
| /* vide */
;

attribut
: NOM att_type defaut_declaration {  }
;

att_type  
: CDATA  { }
| TOKENTYPE { }
| type_enumere { }
;

type_enumere
: OUVREPAR liste_enum_plus FERMEPAR { }
;

liste_enum_plus
: liste_enum BARRE NOM { }
;

liste_enum
: NOM { }
| liste_enum BARRE NOM { }
;

defaut_declaration
: DECLARATION {}
| VALEUR { } 
| FIXED VALEUR { } 
;

/* I.3.1.2 */
card_opt
: PTINT { printf("card_opt\n"); $$ = new enum NodeCard; *($$) = ZERO_ONE; }
| AST { printf("card_opt\n"); $$ = new enum NodeCard; *($$) = ZERO_PLUS; }
| PLUS { printf("card_opt\n"); $$ = new enum NodeCard; *($$) = ONE_PLUS; }
| /*vide*/ { printf("card_opt\n"); $$ = new enum NodeCard; *($$) = ONE; }
;

element
: ELEMENT NOM contentspec SUP { printf("creation d'un element \n"); $$ = new DtdDeclaration(); $$->name = std::string($2); $$->elementType = $3->first; $$->tree = $3->second;} 
;

contentspec
: EMPTY {printf("contentspec\n");  $$ = new std::pair<enum ElementType, DtdComposite*>(); $$->first = ELM_EMPTY; $$->second = NULL;}
| ANY { printf("contentspec\n");$$ = new std::pair<enum ElementType, DtdComposite*>(); $$->first = ELM_ANY; $$->second = NULL;}
| children { printf("contentspec\n");$$ = new std::pair<enum ElementType, DtdComposite*>(); $$->first = ELM_CHILDREN; $$->second = (DtdComposite*) $1;}
| mixed {printf("contentspec\n"); $$ = new std::pair<enum ElementType, DtdComposite*>(); $$->first = ELM_PCDATA; $$->second = (DtdComposite*) $1;}
;

children
: choice card_opt { printf("children\n"); $$ = $1; $$->card = *($2); delete($2);}
| seq card_opt { printf("children\n"); $$ = $1; $$->card = *($2); delete($2);}
;

cp
: NOM card_opt { 	printf("cp\n"); DtdElement *e = new DtdElement();
			e->card = *($2);
			delete($2);
			e->name = std::string($1);
			$$ = e;
		}
| children { printf("cp\n");$$ = $1 ;}
;

choice
: OUVREPAR cp liste_choice FERMEPAR { DtdComposite *comp = new DtdComposite(); comp->compositeType = CHC; comp->appendChild($2); comp->appendChildren(*($3)); $$=comp;}
;

seq
: OUVREPAR cp liste_seq_opt FERMEPAR { DtdComposite *comp = new DtdComposite(); comp->compositeType = SEQ; comp->appendChild($2); comp->appendChildren(*($3)); $$ = comp;}
;

liste_choice
: liste_choice BARRE cp { $$ = $1; $$->push_back($3);}
| BARRE cp { $$ = new std::list<DtdNode*>(); $$->push_back($2);}
;

liste_seq_opt
: liste_seq_opt VIRGULE cp { $$ = $1; $$->push_back($3);}
| /*vide*/ { $$ = new std::list<DtdNode*>();}
;

mixed
: OUVREPAR PCDATA barre_nom FERMEPAR AST { DtdComposite *comp = new DtdComposite(); comp->compositeType = CHC; comp->appendChildren(*($3));}
| OUVREPAR PCDATA FERMEPAR ast_opt { $$ = NULL; }
;

barre_nom
: barre_nom BARRE NOM { $$ = $1; DtdElement *e = new DtdElement(); e->name = std::string($3); $$-> push_back(e); }
| BARRE NOM { $$ = new std::list<DtdNode*>(); DtdElement *e = new DtdElement(); e->name = std::string($2); $$-> push_back(e); }
;

ast_opt
: AST { printf("ast_opt\n"); $$ = new enum NodeCard; *($$) = ZERO_PLUS ; }
| /*vide*/ { printf("ast_opt\n");$$ = new enum NodeCard; *($$) = ONE ; }
;

%%

/*

int main(int argc, char **argv)
{
  int err;

  dtd_debug = 1; // pour désactiver l'affichage de l'exécution du parser LALR, commenter cette ligne

  err = dtd_parse();
  if (err != 0) printf("Parse ended with %d error(s)\n", err);
        else  printf("Parse ended with success\n", err);
  return 0;
}
*/

int dtd_wrap(void)
{
  return 1;
}

void dtd_error(DtdTree** arbreDTD,char *msg)
{
  fprintf(stderr, "%s\n", msg);
}

